# Copyright (c) 2006 "Gardiner"
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
# of the Software, and to permit persons to whom the Software is furnished to do
# so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.

def println(str)
	print str + "\n"
end

class Array
	def random_elements(n, unique = true)
		indexes = []
		
		while indexes.length < n do
			idx = rand(length)
			indexes.push(idx) unless unique && indexes.member?(idx)
		end
		
		return indexes.collect { |i| at(i) }
	end
	
	# also see SyncEnumerator in generator library
	# but this is faster in some cases
	def Array.parallel_collect(*rest)
		collected = []
		lengths = rest.collect { |arg| arg.length }
		
		lengths.min.times {|i|
			collected << yield(*(rest.collect { |arg| arg[i] }))
		}
		
		return collected
	end
	
	def max_index()
		maxValue = nil
		maxIndex = nil
		each_with_index { |val, idx| 
			if !maxValue || val > maxValue 
				maxIndex = idx
				maxValue = val
			end
			}	
		return maxIndex
	end
	
	def detect_with_index()
		theIndex = nil
		each_with_index { |val, idx|
			if yield(val)
				theIndex = idx
				break
			end
		}
		
		return theIndex
	end
	
	def inject(n)
		each { |value| n = yield(n, value) }
		n
	end
	
	def sum
		inject(0) { |n, value| n + value }
	end
	
	def product
		inject(1) { |n, value| n * value }
	end
	
	def add(*rest)
		Array.parallel_collect(self, *rest) { |*rest| rest.sum }
	end
	
	def but_last
		self[0..-2]
	end
end

module Quantifiers
	def always()
		cond = true
		each do |value|
			cond &&= yield(value)
			break unless cond 
		end
		cond
	end
	
	def sometimes()
		cond = false
		each do |value|
			cond ||= yield(value)
			break if cond
		end
		cond
	end
	
	def never(&block)
		!sometimes(&block)
	end
end

class Array
	include Quantifiers
end

class Range
	include Quantifiers
end

class Hash
	include Quantifiers
end

class String
	include Quantifiers
end
